﻿using System;
using System.Data;
using System.IO;
using System.Runtime.Serialization;

using PublicDomain.Data.Csv.Metadata;
using PublicDomain.Data.Csv.Properties;

namespace PublicDomain.Data.Csv
{
    public class CsvCommand : IDbCommand
    {
        public CsvCommand(string commandText, CsvConnection csvConnection)
        {
            this.CommandText = commandText;
            this.Connection = csvConnection;
        }

        public CsvCommand(string commandText)
            : this(commandText, null)
        {
        }

        public CsvCommand()
            : this(null, null)
        {
        }

        public CommandType CommandType
        {
            get { return CommandType.TableDirect; }
            set { throw new CsvCommandException(Resources.SetCsvCommandCommandTypeError); }
        }

        public string CommandText { get; set; }

        public IDbConnection Connection { get; set; }

        public int CommandTimeout
        {
            get
            {
                return -1;
            }

            set
            {
            }
        }

        public IDataParameterCollection Parameters
        {
            get { return null; }
        }

        public IDbTransaction Transaction
        {
            get
            {
                return null;
            }

            set
            {
            }
        }

        public UpdateRowSource UpdatedRowSource
        {
            get
            {
                return UpdateRowSource.None;
            }

            set
            {
            }
        }

        public IDataReader ExecuteReader(CommandBehavior behavior)
        {
            throw new NotImplementedException();
        }

        public IDataReader ExecuteReader()
        {
            var csvFilePath = this.ResolveCsvFilePath();
            var csvDataFormat = this.ResolveCsvDataFormat(this.CommandText);
            var headerRowsCount = this.ResolveHeaderRowsCount();
            var delimiter = this.ResolveDelimiter();
            var parsingOptions = this.ResolveParsingOptions();

            return new CsvDataReader(csvFilePath, csvDataFormat, headerRowsCount, delimiter, parsingOptions);
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        public void Prepare()
        {
            throw new NotImplementedException();
        }

        public void Cancel()
        {
            throw new NotImplementedException();
        }

        public IDbDataParameter CreateParameter()
        {
            throw new NotImplementedException();
        }

        public int ExecuteNonQuery()
        {
            throw new NotImplementedException();
        }

        public object ExecuteScalar()
        {
            throw new NotImplementedException();
        }

        protected virtual void Dispose(bool disposing)
        {
        }

        private string ResolveCsvFilePath()
        {
            var result = this.CommandText;
            if (this.Connection != null && !String.IsNullOrWhiteSpace(this.Connection.Database) && String.IsNullOrWhiteSpace(Path.GetDirectoryName(result)))
            {
                result = Path.Combine(this.Connection.Database, this.CommandText);
            }

            return result;
        }

        private CsvDataFormat ResolveCsvDataFormat(string commandText)
        {
            var csvConnection = this.Connection as CsvConnection;
            if (csvConnection != null) 
            {
                if (!String.IsNullOrWhiteSpace(csvConnection.SchemataFilePath))
                {
                    var dataContractSerializer = new DataContractSerializer(typeof(CsvSchemata));
                    using (var fileStream = new FileStream(csvConnection.SchemataFilePath, FileMode.Open,  FileAccess.Read))
                    {
                        var csvSchemata = (CsvSchemata)dataContractSerializer.ReadObject(fileStream);

                        if (csvSchemata != null)
                        {
                            return csvSchemata.GetCsvFileDataFormat(commandText);
                        }
                    }
                }
            }

            return null;
        }

        private int? ResolveHeaderRowsCount()
        {
            var csvConnection = this.Connection as CsvConnection;
            if (csvConnection != null)
            {
                return csvConnection.HeaderRowsCount;
            }

            return null;
        }

        private char? ResolveDelimiter()
        {
            var csvConnection = this.Connection as CsvConnection;
            if (csvConnection != null)
            {
                return csvConnection.Delimiter;
            }

            return null;
        }

        private CsvParsingOptions ResolveParsingOptions()
        {
            var csvConnection = this.Connection as CsvConnection;
            if (csvConnection != null)
            {
                return csvConnection.ParsingOptions;
            }

            return CsvParsingOptions.None;
        }
    }
}
